package pri.zxx.learndemo.threademo.base;

import lombok.extern.slf4j.Slf4j;
import pri.zxx.webdemo.utils.TimeUtils;

import java.util.LinkedList;
import java.util.stream.IntStream;

/**
 * @author Twilight
 * @desc
 * @createTime 2020-06-27-12:00
 */
@Slf4j
public class WaitNotifyDemo {
    public static void main(String[] args) {
        EventQueue eventQueue = new EventQueue(100);

        IntStream.range(0, 2)
                .mapToObj((s) -> new Thread(() -> WaitNotifyDemo.insertBrief(eventQueue), "insert_" + s))
                .forEach(Thread::start);
        IntStream.range(0, 3)
                .mapToObj((s) -> new Thread(() -> WaitNotifyDemo.takeBrief(eventQueue), "take_" + s))
                .forEach(Thread::start);

        new Thread(() -> sizeBrief(eventQueue), "size--").start();

        TimeUtils.pause(1, 0, 0);
    }

    private static void sizeBrief(EventQueue eventQueue) {
        while (true) {
            log.warn("size----->>>>" + eventQueue.size());
            TimeUtils.pause(0, 1, 0);
        }
    }

    private static void takeBrief(EventQueue eventQueue) {
        while (true) {
            eventQueue.get();
            TimeUtils.pause(0, 0, 200);
        }
    }

    private static void insertBrief(EventQueue eventQueue) {
        while (true) {
            eventQueue.insert(new EventQueue.Event());
            TimeUtils.pause(0, 0, 50);
        }
    }
}


@Slf4j
class EventQueue {

    private static final int DEFAULT_NUM = 10;
    private final int max;
    private final LinkedList<Event> eventContain = new LinkedList<>();

    public EventQueue(int max) {
        this.max = max;
    }

    public EventQueue() {
        max = DEFAULT_NUM;
    }

    /**
     * size()
     */
    public Integer size() {
        return eventContain.size();
    }

    /**
     * 放入事件到队列中
     */
    public void insert(Event event) {
        synchronized (eventContain) {
            if (eventContain.size() >= max) {
                //如果大于等于最大值，则等待
                try {
                    log.warn(Thread.currentThread().getName() + "#放入等待中");
                    eventContain.wait();
                } catch (InterruptedException e) {
                    log.error("线程被中断", e);
                }
            }
            log.warn(Thread.currentThread().getName() + "#放入事件");
            eventContain.addFirst(event);
            eventContain.notifyAll();
        }
    }

    /**
     * 消费事件
     */
    public Event get() {
        synchronized (eventContain) {
            if (eventContain.isEmpty()) {
                try {
                    log.warn(Thread.currentThread().getName() + "#拿出等待中");
                    eventContain.wait();
                } catch (InterruptedException e) {
                    log.error("线程被中断", e);
                }
            }
            log.warn(Thread.currentThread().getName() + "#拿出事件");
            Event event = eventContain.removeLast();
            eventContain.notifyAll();
            return event;
        }
    }

    static class Event {
    }
}